// This is the main DLL file.

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <string>
#include <Windows.h>

#include "NativeConnector.h"

#include "ToolBox.h"

using namespace std;

using namespace System::Diagnostics;

using namespace Tradex::Connectivity;
using namespace Tradex::Connectivity::ConnectorModel;

#define GOOD 0
#define BAD  1

namespace Tradex {
	namespace Connectivity {
		namespace Rithmic {

			NativeConnector::NativeConnector (RithmicConnector^ pManagedConnector) {
				pManaged = pManagedConnector;
				pREngine = nullptr;
				connectionCount = 0;

				pMarketModeMap = gcnew System::Collections::Generic::Dictionary<System::String^, Tradex::Market::MarketModes> ();
				pMarketModeMap->Add ("Open", Tradex::Market::MarketModes::Open);
				pMarketModeMap->Add ("Halted", Tradex::Market::MarketModes::Halted);
				pMarketModeMap->Add ("End of Day", Tradex::Market::MarketModes::Closed);
				pMarketModeMap->Add ("Pre-Open", Tradex::Market::MarketModes::PreOpen);
				pMarketModeMap->Add ("No Cancel", Tradex::Market::MarketModes::NoCancel);

				pCompletionReasonMap = gcnew System::Collections::Generic::Dictionary<System::String^,Tradex::Trading::OrderStatus> ();
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_CANCEL),Tradex::Trading::OrderStatus::CompleteCancel);
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_REJECT),Tradex::Trading::OrderStatus::CompleteReject);
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_FILL),Tradex::Trading::OrderStatus::CompleteFill);
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_FAILURE),Tradex::Trading::OrderStatus::CompleteFailure);
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_UNKNOWN),Tradex::Trading::OrderStatus::CompleteUnknown);
				pCompletionReasonMap->Add (ToolBox::CreateNString(sCOMPLETION_REASON_PFBC),Tradex::Trading::OrderStatus::CompletePartialFill);

				pLineStatusMap = gcnew System::Collections::Generic::Dictionary<System::String^,Tradex::Trading::OrderStatus> ();
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_OPEN_PENDING),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_OPEN),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MOD_TRIGGER_PENDING),Tradex::Trading::OrderStatus::Waiting);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_TRIGGER_PENDING),Tradex::Trading::OrderStatus::Waiting);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_PARTIAL),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_CANCEL_PENDING),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_COMPLETE),Tradex::Trading::OrderStatus::CompleteUnknown);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFY_PENDING),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFIED),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_SENT_TO_ORM),Tradex::Trading::OrderStatus::Waiting);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_ORM_RELEASE_PENDING),Tradex::Trading::OrderStatus::Waiting);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_ORM_ORDER_RELEASED),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_ORDER_SENT_TO_EXCH),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_CANCEL_SENT_TO_EXCH),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFY_SENT_TO_EXCH),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_ORDER_RCVD_BY_EXCH_GWAY),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_CANCEL_RCVD_BY_EXCH_GWAY),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFY_RCVD_BY_EXCH_GWAY),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_ORDER_RECEIVED),Tradex::Trading::OrderStatus::Submitted);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFY_RECEIVED),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_CANCEL_RECEIVED),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_MODIFY_FAILED),Tradex::Trading::OrderStatus::Active);
				pLineStatusMap->Add (ToolBox::CreateNString(sLINE_STATUS_CANCEL_FAILED),Tradex::Trading::OrderStatus::Active);
			};

			NativeConnector::~NativeConnector () {
				if (pREngine) {
					delete pREngine;
				};
				pManaged = NULL;
			};

			/**
			*	From here on: Internal Support methods - not many, but sometimes usefull.
			*/

			Tradex::Trading::OrderUpdate^ NativeConnector::ProcessLineInfo (LineInfo *pLineInfo, bool current) {
				String^ pKeyStr = ToolBox::CreateNString (pLineInfo->sUserMsg);
				String^ pStatusStr = ToolBox::CreateNString (pLineInfo->sStatus);
				Tradex::Trading::OrderStatus status = Tradex::Trading::OrderStatus::Unknown;
				if (!String::IsNullOrEmpty (pStatusStr)) {
					pLineStatusMap->TryGetValue (pStatusStr, status);

					if (status == Tradex::Trading::OrderStatus::CompleteUnknown) {
						String^ pStatusCompleteStr = ToolBox::CreateNString (pLineInfo->sCompletionReason);
						if (!pCompletionReasonMap->TryGetValue (pStatusCompleteStr, status)) {
							status = Tradex::Trading::OrderStatus::CompleteUnknown;
						}
						if (!String::IsNullOrEmpty(pKeyStr)) {
							if (current == true) {
								// Terminal state. We need to remove our internal ID from the dictionary
								pManaged->pOrderCodeMap->Remove (pKeyStr);
								Console::WriteLine ("* * * * * ID removed: " + pKeyStr);
							}
						}
					} else {
						if (!String::IsNullOrEmpty(pKeyStr)) {
							if (current == true) {
								// Non-Terminal state: we need to make sure we can find the order number by our GUID.
								pManaged->pOrderCodeMap->Add (pKeyStr, pLineInfo->iOrderNum);
								Console::WriteLine ("* * * * * ID set/added: " + pKeyStr);
							}
						}
					}
				} else {
					status = Tradex::Trading::OrderStatus::Unknown;
				}

				String^ pTextStr = ToolBox::CreateNString (pLineInfo->sText);
				pTextStr = pStatusStr + " " + pTextStr;
				pTextStr = pTextStr->Trim ();

				Tradex::Trading::OrderUpdate^ pUpdate = gcnew Tradex::Trading::OrderUpdate (
					ToolBox::CreateNDateTime (pLineInfo->iSsboe, pLineInfo->iUsecs),
					status,
					pLineInfo->iFilled,
					pLineInfo->dAvgFillPrice,
					pLineInfo->iUnfilled,
					pTextStr
				);
				return pUpdate;
			}

			/**
			*	From here on: Functions that will be forwarded to the the Rithmic Engine..
			*/

			void NativeConnector::Connect (REngineParams* pEngineParams, LoginParams* pLoginParams) {
				if (pREngine != NULL) {
					throw gcnew InvalidOperationException ("Sorry, already connected");
				}
				try {
					pREngine = new REngine (pEngineParams);
          		} catch (OmneException&) {
					pManaged->OnLogEntry (
						TraceLevel::Error,
						"Connector Setup Error",
						"Check network and parameters",
						nullptr,
						nullptr
					);
					pManaged->OnStatusUpdate (ConnectionStatusCode::Error, "Connection Setup Error - check network and parameters");
					//int eCode = oEx.getErrorCode();
					//switch (eCode) {
					//	case 6: {
					//		throw gcnew ArgumentException ("Engine Setup reports: Bad Input (parameters)", "pEngineParams");
					//	}
					//	default:
					//		throw gcnew ArgumentException ("Engine Setup Exception");
					//}
				}
				int iCode;
				int ret;
				ret = pREngine -> login(pLoginParams, &iCode);
				if (!ret) {
					delete pREngine;
					pREngine = NULL;
					//throw gcnew ArgumentException ("Login failed.");
					pManaged->OnStatusUpdate (ConnectionStatusCode::ForceDisconnect, "Login failed.");
				}
			};

			void NativeConnector::Disconnect () {
				if (pREngine == 0) {
					throw gcnew InvalidOperationException ("Sorry, not connected");
				}
				int iCode;
				pREngine->logout (&iCode);
				delete pREngine;
				pREngine = NULL;
			}

			void ProcessAiCode (int aiCode) {
				if (aiCode == API_OK) {
					return;
				}
				switch (aiCode) {
					case API_ALREADY_EXISTS:
						return;
					case API_NO_HANDLE:
						throw gcnew InvalidOperationException ("The operation is invalid at this time - are you logged in?");
					case API_MINOR_ERROR:
						throw gcnew ArgumentException ("Internal Error (reported as minor - check parameters");
					default:
						throw gcnew ArgumentException ("Connection operation failed - bad argument?");
				}
			}

			/**
			* From here on: Callback methods, that the Rithmic Engine will call (on her own thread).
			*/

			int NativeConnector::Alert(AlertInfo *pInfo, void *pContext, int *aiCode) {
				String^ _exchange = ToolBox::CreateNString (pInfo->sExchange);
				String^ _ticker = ToolBox::CreateNString (pInfo->sTicker);
				String^ _message = ToolBox::CreateNString (pInfo->sMessage);

				TraceLevel _traceLevel = TraceLevel::Verbose;
				switch (pInfo->iAlertType) {
					case ALERT_CONNECTION_OPENED:
						_traceLevel = TraceLevel::Info;
						connectionCount ++;
						UpdateConnectionStatus ();
					case ALERT_CONNECTION_CLOSED:
						_traceLevel = TraceLevel::Info;
						connectionCount --;
						UpdateConnectionStatus ();
						break;
					case ALERT_CONNECTION_BROKEN:
						_traceLevel = TraceLevel::Warning;
						connectionCount --;
						UpdateConnectionStatus ();
						break;
					case ALERT_LOGIN_COMPLETE:
						pManaged->OnStatusUpdate (ConnectionStatusCode::Connected, _message);
						_traceLevel = TraceLevel::Info;
						break;
					case ALERT_LOGIN_FAILED:
						pManaged->OnStatusUpdate (ConnectionStatusCode::ForceDisconnect, _message);
						_traceLevel = TraceLevel::Error;
						break;
					case ALERT_QUIET_HEARTBEAT:
						_traceLevel = TraceLevel::Warning;
						break;
					case ALERT_SERVICE_ERROR:
						// Infrastructure indicates a request is invalid... this is not a connection error,
						// but for example an invalid ticker symbol.
						_traceLevel = TraceLevel::Error;
						break;
					case ALERT_FORCED_LOGOUT:
						pManaged->OnStatusUpdate (ConnectionStatusCode::Disconnected, _message);
						_traceLevel = TraceLevel::Warning;
						break;
					case ALERT_SHUTDOWN_SIGNAL:
						pManaged->OnStatusUpdate (ConnectionStatusCode::ForceDisconnect, _message);
						 _traceLevel = TraceLevel::Warning;
						break;
				}
				
				pManaged->OnLogEntry (
					_traceLevel,
					"Alert",
					_message,
					nullptr,
					_ticker
				);

				*aiCode = API_OK;
				return (OK);
			};

		     /*   ----------------------------------------------------------------   */

			int NativeConnector::AskQuote(AskInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Ask,
					pInfo->dPrice, pInfo->iSize
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::BestAskQuote(AskInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::BestAsk,
					pInfo->dPrice, pInfo->iSize
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::BestBidQuote(BidInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::BestBid,
					pInfo->dPrice, pInfo->iSize
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::BidQuote(BidInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Bid,
					pInfo->dPrice, pInfo->iSize
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::ClosePrice(ClosePriceInfo *pInfo, void *pContext, int * aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Close,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::ClosingIndicator(ClosingIndicatorInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Closing,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::HighPrice(HighPriceInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::High,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::LimitOrderBook(LimitOrderBookInfo *pInfo, void *pContext, int *aiCode) {
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::LowPrice(LowPriceInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Low,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::MarketMode(MarketModeInfo * pInfo, void *pContext, int *aiCode) {
				Tradex::Market::MarketModes marketMode = Tradex::Market::MarketModes::Error;

				String^ pInstrument = ToolBox::CreateNString (pInfo->sTicker);
				String^ pMarket = ToolBox::CreateNString (pInfo->sExchange);

				String^ modeString = ToolBox::CreateNString (pInfo->sMarketMode);
				
				if (!pMarketModeMap->TryGetValue (modeString, marketMode)) {
					marketMode = Tradex::Market::MarketModes::Error;
				}

				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Mode,
					marketMode,
					modeString
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				if (marketMode == Tradex::Market::MarketModes::Error) {
					pManaged->OnLogEntry (
						TraceLevel::Error,
						"Invalid / Unrecognized Market Mode",
						"Mode String: " + modeString,
						nullptr,
						pMarket +  "@" + pInstrument
					);
				}

				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::OpenPrice(OpenPriceInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Open,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::OpeningIndicator(OpeningIndicatorInfo * pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Opening,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::RefData(RefDataInfo *pInfo, void *pContext, int *aiCode) {
				if (pInfo->iRpCode != 0) {
					// non zero means error..... possibly no data or something.... just skip it.
					*aiCode = API_OK;
					return (OK);
				}
				String^ instrumentTypeString = ToolBox::CreateNString (pInfo->sInstrumentType);
				Tradex::Market::InstrumentType instrumentType = Tradex::Market::InstrumentType::Undefined;
				String^ optionTypeString = ToolBox::CreateNString (pInfo->sPutCallIndicator);
				Tradex::OptionType optionType = Tradex::OptionType::None;

				if (!String::IsNullOrEmpty(instrumentTypeString)) {
					instrumentType = safe_cast<Tradex::Market::InstrumentType> (Enum::Parse (
						Tradex::Market::InstrumentType::typeid, instrumentTypeString, true));
				}
				if (!String::IsNullOrEmpty(optionTypeString)) {
					optionType = safe_cast<Tradex::OptionType> (Enum::Parse (
						Tradex::OptionType::typeid, optionTypeString, true));
				}

				InstrumentInfo^ pInstrument = gcnew InstrumentInfo (
					instrumentType,
					ToolBox::CreateNString (pInfo->sDescription),

					ToolBox::CreateNString (pInfo->sCurrency),
					pInfo->dSinglePointValue,

					optionType,
					pInfo->dStrikePrice,

					ToolBox::CreateNString (pInfo->sProductCode),
					ToolBox::CreateNString (pInfo->sExpiration)
				);
				pManaged->OnReferenceUpdate (					
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pInstrument,
					nullptr
				);	
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::SettlementPrice(SettlementPriceInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Settlement,
					pInfo->dPrice, 0
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TradeCondition(RApi::TradeInfo *pInfo, void *pContext, int *aiCode) {
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TradePrint(RApi::TradeInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Trade,
					pInfo->dPrice, pInfo->iSize
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TradeReplay(TradeReplayInfo * pInfo, void *pContext, int *aiCode) {
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TradeVolume(TradeVolumeInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Market::Activity^ pActivity = gcnew Tradex::Market::Activity (
					ToolBox::CreateNDateTime(pInfo->iSsboe, pInfo->iUsecs),
					Tradex::Market::ActivityType::Volume,
					0, pInfo->iTotalVolume
				);
				pManaged->OnActivity (
					gcnew InstrumentKey (
						ToolBox::CreateNString (pInfo->sExchange),
						ToolBox::CreateNString (pInfo->sTicker)
					),
					pActivity
				);
				*aiCode = API_OK;
				return (OK);
			};

			/*   ----------------------------------------------------------------   */

			int NativeConnector::AccountList(AccountListInfo *pInfoList, void *pContext, int *aiCode) {
				//for (int i = 0; i < pInfoList->iArrayLen; i++) {
				//	//AccountInfo* pInfo = &(pInfoList->asAccountInfoArray[i]);
				//	//pManaged->OnAccountUpdate (ToolBox::CreateTAccountKey (*pInfo), nullptr, nullptr);
				//	
				//	//int aiCode2;
				//	//pREngine->subscribeAccount (pInfo, &aiCode2);
				//	//pREngine->replayPnl (pInfo, &aiCode2);
				//}
				*aiCode = API_OK;
				return (OK);
			};

			/*   ----------------------------------------------------------------   */

			int NativeConnector::ExecutionReplay(ExecutionReplayInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Trading::AccountKey^ pAccount = ToolBox::CreateTAccountKey (pInfo->oAccount);
				for (int i = 0; i < pInfo->iArrayLen; i++) {
					OrderFillReport* pReport = &pInfo->asFillReportArray[i];

					Tradex::Trading::OrderKey^ pOrderKey = Tradex::Trading::OrderKey::ToOrderKey (
						ToolBox::CreateNString (pReport->sUserMsg)
					);
					Tradex::Trading::OrderId^ pOrderId = gcnew Tradex::Trading::OrderId (
						System::Convert::ToString (pReport->iOrderNum)
					);
					Tradex::Trading::OrderExecution^ pFill = gcnew Tradex::Trading::OrderExecution (
						ToolBox::CreateNDateTime (pReport->iSsboe, pReport->iUsecs),
						OrderExecutionType::Fill,
						pReport->iFillSize,
						pReport->dFillPrice,
						ToolBox::CreateNString (pReport->sFillType),
						ToolBox::CreateNString (pReport->sSettlementCurrency),
						ToolBox::CreateNString (pReport->sSettlementDate)
					);
					pManaged->OnOrderUpdate (pAccount, pOrderKey, pOrderId, nullptr, pFill);
				}

				*aiCode = API_OK;
				return (OK);

				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::LineUpdate(LineInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Trading::OrderKey^ pOrderKey = Tradex::Trading::OrderKey::ToOrderKey (
					ToolBox::CreateNString (pInfo->sUserMsg)
				);
				Tradex::Trading::OrderId^ pOrderId = gcnew Tradex::Trading::OrderId (
					System::Convert::ToString (pInfo->iOrderNum)
				);
				Tradex::Trading::AccountKey^ pAccountKey = ToolBox::CreateTAccountKey (pInfo->oAccount);
				Tradex::Trading::OrderUpdate^ pUpdate = ProcessLineInfo (pInfo, true);

				pManaged->OnOrderUpdate (pAccountKey, pOrderKey, pOrderId, pUpdate, nullptr);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::OpenOrderReplay(OrderReplayInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Trading::AccountKey^ pAccountKey = ToolBox::CreateTAccountKey (pInfo->oAccount);
				List<Tradex::Trading::OrderUpdate^> ^pUpdates = gcnew List<Tradex::Trading::OrderUpdate^> ();
				for (int i = 0; i < pInfo->iArrayLen; i++) {
					LineInfo *pLine = &pInfo->asLineInfoArray[i];
					Tradex::Trading::OrderUpdate^pUpdate = ProcessLineInfo (pLine, true);
					pUpdates->Add (pUpdate);
				}
				if (pUpdates->Count != 0) {
					pManaged->OnOrdersUpdate(pAccountKey, pUpdates->ToArray ());
				}
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::OrderReplay(OrderReplayInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Trading::AccountKey^ pAccountKey = ToolBox::CreateTAccountKey (pInfo->oAccount);
				for (int i = 0; i < pInfo->iArrayLen; i++) {
					LineInfo* pReport = &pInfo->asLineInfoArray[i];

					Tradex::Trading::OrderId^ pOrderId = gcnew Tradex::Trading::OrderId (
						System::Convert::ToString (pReport->iOrderNum)
					);

					Tradex::Trading::OrderUpdate^ pUpdate = ProcessLineInfo (pReport, false);
					pManaged->OnOrderUpdate (pAccountKey, nullptr, pOrderId, pUpdate, nullptr);
					LineUpdate (pReport, pContext, aiCode);
				}
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::PnlReplay(PnlReplayInfo *pRInfo, void *pContext, int *aiCode) {
				for (int i = 0; i < pRInfo->iArrayLen; i++) {
					PnlInfo* pInfo = &pRInfo->asPnlInfoArray[i];
					Tradex::Trading::PositionUpdate^ pPosition = gcnew Tradex::Trading::PositionUpdate (
						System::DateTime::UtcNow,
						ToolBox::CreateNString (pInfo->sTicker),
						ToolBox::CreateNString (pInfo->sExchange),
						pInfo->lPosition, pInfo->dAvgOpenFillPrice
					);
					Tradex::Trading::AccountUpdate^ pAccountUpdate = gcnew Tradex::Trading::AccountUpdate (
						pInfo->bAccountBalance == true ? pInfo->dAccountBalance : Double::NaN,
						pInfo->oAccount.pRmsInfo != nullptr ? pInfo->oAccount.pRmsInfo->dCashOnHand : Double::NaN,
						pInfo->bOpenPnl == true ? pInfo->dOpenPnl : Double::NaN,
						pInfo->bClosedPnl == true ? pInfo->dClosedPnl : Double::NaN,
						pInfo->bBuyMargin == true ? pInfo->dBuyMargin : Double::NaN,
						pInfo->bSellMargin == true ? pInfo->dSellMargin : Double::NaN
					);
					pManaged->OnAccountUpdate (
						ToolBox::CreateTAccountKey(pInfo->oAccount),
						pAccountUpdate,
						pPosition
					);
				}
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::PnlUpdate(PnlInfo *pInfo, void *pContext, int *aiCode) {
				Tradex::Trading::PositionUpdate^ pPosition = gcnew Tradex::Trading::PositionUpdate (
					System::DateTime::UtcNow,
					ToolBox::CreateNString (pInfo->sTicker),
					ToolBox::CreateNString (pInfo->sExchange),
					pInfo->lPosition, pInfo->dAvgOpenFillPrice
				);
				Tradex::Trading::AccountUpdate^ pAccountUpdate = gcnew Tradex::Trading::AccountUpdate (
					pInfo->bAccountBalance == true ? pInfo->dAccountBalance : Double::NaN,
					pInfo->oAccount.pRmsInfo != nullptr ? pInfo->oAccount.pRmsInfo->dCashOnHand : Double::NaN,
					pInfo->bOpenPnl == true ? pInfo->dOpenPnl : Double::NaN,
					pInfo->bClosedPnl == true ? pInfo->dClosedPnl : Double::NaN,
					pInfo->bBuyMargin == true ? pInfo->dBuyMargin : Double::NaN,
					pInfo->bSellMargin == true ? pInfo->dSellMargin : Double::NaN
				);
				pManaged->OnAccountUpdate (
					ToolBox::CreateTAccountKey(pInfo->oAccount),
					pAccountUpdate,
					pPosition
				);
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::PriceIncrUpdate(PriceIncrInfo *pInfo, void *pContext, int *aiCode) {
				if (pInfo->iRpCode != 0) {
					// non zero means error..... possibly no data or something.... just skip it.
					*aiCode = API_OK;
					return (OK);
				}
				System::Collections::Generic::List<InstrumentPricingItem^>^ pItems =
					gcnew System::Collections::Generic::List<InstrumentPricingItem^>();
				for (int i=0; i<pInfo->iArrayLen; i++) {
					PriceIncrRow* row = &(pInfo->asPriceIncrArray[i]);

					double increment = row->dPriceIncr;
					if (increment == 0) {
						continue;
					}
					byte precision = (byte) row->iPrecision;

					// Determine minimum price
					double minPrice = Double::NegativeInfinity;
					switch (row->iFirstOperator) {
						case OP_NONE:
							break;
						case OP_GREATER_THAN:
							minPrice = row->dFirstPrice + increment;
							break;
						case OP_GREATER_THAN_OR_EQUAL_TO:
							minPrice = row->dFirstPrice;
							break;
						default:
							System::Diagnostics::Debugger::Break ();
							break;
					}

					// Determine maximum price
					double maxPrice = Double::PositiveInfinity;
					switch (row->iLastOperator) {
						case OP_NONE:
							break;
						case OP_LESS_THAN:
							maxPrice = row->dLastPrice - increment;
							break;
						case OP_LESS_THAN_OR_EQUAL_TO:
							maxPrice = row->dLastPrice;
							break;
						default:
							System::Diagnostics::Debugger::Break ();
							break;
					}

					//Tradex::Operator firstOperator = ToolBox::GetTOperator(pInfo->asPriceIncrArray[i].iFirstOperator);
					//Tradex::Operator lastOperator = ToolBox::GetTOperator(pInfo->asPriceIncrArray[i].iLastOperator);
					InstrumentPricingItem^ pItem = gcnew InstrumentPricingItem (
						minPrice, maxPrice, increment, precision
					);
					pItems->Add (pItem);
				};
				if (pItems->Count != 0) {
					InstrumentPricing^ pPricing = gcnew InstrumentPricing (
						pItems->ToArray ()
					);
					pManaged->OnReferenceUpdate (
						gcnew InstrumentKey (
							ToolBox::CreateNString (pInfo->sExchange),
							ToolBox::CreateNString (pInfo->sTicker)
						),
						nullptr,
						pPricing
					);
				}
		
				*aiCode = API_OK;
				return (OK);
			};

			/*   ----------------------------------------------------------------   */

			int NativeConnector::BustReport(OrderBustReport *pReport, void *pContext, int *aiCode) {
				Tradex::Trading::AccountKey^ pAccountKey = ToolBox::CreateTAccountKey (pReport->oAccount);
				String^ pKeyStr = ToolBox::CreateNString (pReport->sUserMsg);
				Tradex::Trading::OrderKey^ pOrderKey = Tradex::Trading::OrderKey::ToOrderKey (pKeyStr);
				Tradex::Trading::OrderId^ pOrderId = gcnew Tradex::Trading::OrderId (
						System::Convert::ToString (pReport->iOrderNum)
				);
				Tradex::Trading::OrderExecution^ pFill = gcnew Tradex::Trading::OrderExecution (
					ToolBox::CreateNDateTime (pReport->iSsboe, pReport->iUsecs),
					OrderExecutionType::Bust,
					pReport->iFillSize,
					pReport->dFillPrice,
					ToolBox::CreateNString (pReport->sFillType),
					ToolBox::CreateNString (pReport->sSettlementCurrency),
					ToolBox::CreateNString (pReport->sSettlementDate)
				);
				pManaged->OnOrderUpdate (pAccountKey, pOrderKey, pOrderId, nullptr,  pFill);

				*aiCode = API_OK;
				return (OK);			};

			int NativeConnector::CancelReport(OrderCancelReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Cancel Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::FailureReport(OrderFailureReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Failure Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::FillReport(OrderFillReport *pReport, void *pContext, int *aiCode) {
				Tradex::Trading::AccountKey^ pAccountKey = ToolBox::CreateTAccountKey (pReport->oAccount);
				String^ pKeyStr = ToolBox::CreateNString (pReport->sUserMsg);
				Tradex::Trading::OrderKey^ pOrderKey = Tradex::Trading::OrderKey::ToOrderKey (pKeyStr);
				Tradex::Trading::OrderId^ pOrderId = gcnew Tradex::Trading::OrderId (
					System::Convert::ToString (pReport->iOrderNum)
				);
				Tradex::Trading::OrderExecution^ pFill = gcnew Tradex::Trading::OrderExecution (
					ToolBox::CreateNDateTime (pReport->iSsboe, pReport->iUsecs),
					OrderExecutionType::Fill,
					pReport->iFillSize,
					pReport->dFillPrice,
					ToolBox::CreateNString (pReport->sFillType),
					ToolBox::CreateNString (pReport->sSettlementCurrency),
					ToolBox::CreateNString (pReport->sSettlementDate)
				);
				pManaged->OnOrderUpdate (pAccountKey, pOrderKey, pOrderId, nullptr, pFill);

				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::ModifyReport(OrderModifyReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Modify Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::NotCancelledReport(OrderNotCancelledReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Not Cancelled Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::NotModifiedReport(OrderNotModifiedReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Not Modified Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::RejectReport(OrderRejectReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Reject Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::StatusReport(OrderStatusReport *pReport, void *pContext, int *aiCode) {
				// We ignore that - we get all interesting info from the LineUpdate. This only tells us how
				// many items were submitted to the exchange in what time. Redundant information?
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TradeCorrectReport(OrderTradeCorrectReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Trade Correct Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TriggerPulledReport(OrderTriggerPulledReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Trigger Pulled Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::TriggerReport(OrderTriggerReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Trigger Report");
				*aiCode = API_OK;
				return (OK);
			};

			int NativeConnector::OtherReport(RApi::OrderReport *pReport, void *pContext, int *aiCode) {
				Console::WriteLine ("Other Report");
				*aiCode = API_OK;
				return (OK);
			};

			/*   ----------------------------------------------------------------   */

			int NativeConnector::SodUpdate(SodReport *pReport, void *pContext, int *aiCode) {
				*aiCode = API_OK;
				return (OK);
			};

			/*   ----------------------------------------------------------------   */

			void NativeConnector::SendOrder (OrderParams* pOrderParams) {
				int aiCode;
				pREngine->sendOrderList (pOrderParams, 1, &aiCode);
				ProcessAiCode (aiCode);
			}

			void NativeConnector::CancelOrder (RApi::AccountInfo* pAccount, int orderNr) {
				int aiCode;
				pREngine->cancelOrder (pAccount, orderNr, nullptr, &aiCode);
				ProcessAiCode (aiCode);
			}

			void NativeConnector::CancelOrders (RApi::AccountInfo* pAccount) {
				int aiCode;
				pREngine->cancelAllOrders (pAccount, &aiCode);
				ProcessAiCode (aiCode);
			}


			void NativeConnector::GetAccounts () {
				int aiCode;
				pREngine->getAccounts (&aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::GetAccountOrders (RApi::AccountInfo *pAccount) {
				int aiCode;
				pREngine->replayOpenOrders (pAccount, &aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::ReplayExecutions (RApi::AccountInfo *pAccount, int iStartSsboe, int iEndSsboe) {
				int aiCode;
				pREngine->replayExecutions (pAccount, iStartSsboe, iEndSsboe, &aiCode);
				ProcessAiCode (aiCode);
			}

			void NativeConnector::ReplayOrders (RApi::AccountInfo *pAccount, int iStartSsboe, int iEndSsboe) {
				int aiCode;
				pREngine->replayAllOrders (pAccount, iStartSsboe, iEndSsboe, &aiCode);
				//pREngine->replayAllOrders (pAccount, 1, Int32::MaxValue, &aiCode);
				ProcessAiCode (aiCode);
			}

			void NativeConnector::SubscribeInstrument (tsNCharcb* pExchange, tsNCharcb* pTicker, int iFlags) {
				int aiCode;
				pREngine->subscribe (pExchange, pTicker, iFlags, &aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::UnsubscribeInstrument (tsNCharcb* pExchange, tsNCharcb* pTicker) {
				int aiCode;
				pREngine->unsubscribe (pExchange, pTicker, &aiCode);
				ProcessAiCode(aiCode);
			}


			void NativeConnector::SuspendInput () {
				int aiCode;
				pREngine->suspendInput (&aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::ResumeInput () {
				int aiCode;
				pREngine->resumeInput (&aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::SubscribeExchange (tsNCharcb* pExchange, int iFlags) {
				int aiCode;
				pREngine->subscribeExchange (pExchange, iFlags, &aiCode);
				ProcessAiCode(aiCode);
			}

			void NativeConnector::UnsubscribeExchange (tsNCharcb* pExchange) {
				int aiCode;
				pREngine->unsubscribeExchange (pExchange, &aiCode);
				ProcessAiCode(aiCode);
			}


			void NativeConnector::GetReferenceData (tsNCharcb* symbol, tsNCharcb* exchange) {
				int aiCode;
				pREngine->getRefData (exchange, symbol, &aiCode);
				ProcessAiCode(aiCode);
				pREngine->getPriceIncrInfo  (exchange, symbol, FALSE, &aiCode);
				ProcessAiCode(aiCode);
			}

			bool NativeConnector::IsConnected () {
				return pREngine == nullptr;
			}

			void NativeConnector::UpdateConnectionStatus () {
				switch (connectionCount) {
				case 0:
					pManaged->OnStatusUpdate (ConnectionStatusCode::Disconnected, nullptr);
				case 1:
				case 2:
				case 3:
					pManaged->OnStatusUpdate (ConnectionStatusCode::PartiallyConnected, nullptr);
					break;
				case 4:
					pManaged->OnStatusUpdate (ConnectionStatusCode::Connected, nullptr);
					break;
				}
			}

		}
	}
}